from jqdata import *
# 标题：商品期货策略——海龟交易法
# 作者：Huchian
# 部分代码来自聚宽文章：https://www.joinquant.com/post/9184

import numpy as np

## 初始化函数，设定基准等等
def initialize(context):
    # 设置参数
    set_params(context)
    
    # 初始化标的
    g.si = SecuritiesInfo()
    g.ts = TurtleSystem()

    ### 期货相关设定 ###
    sys1_init_cash = context.portfolio.starting_cash * g.ts.sys1_ratio
    sys2_init_cash = context.portfolio.starting_cash - sys1_init_cash
    set_subportfolios([SubPortfolioConfig(cash=sys1_init_cash, type='futures'),\
                    SubPortfolioConfig(cash=sys2_init_cash, type='futures')])
    # 设定账户为金融账户
    # set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='index_futures')])

    # 期货类每笔交易时的手续费是：买入时万分之0.23,卖出时万分之0.23,平今仓为万分之23
    set_order_cost(OrderCost(open_commission=0.000023, close_commission=0.000023,close_today_commission=0.0023), type='index_futures')
    # 设定保证金比例
    set_option('futures_margin_rate', 0.15)
    # 设定基准
    # 交易参考合约
    future_symbol = 'AG'
    set_benchmark(g.si.get_future_code(future_symbol))

    
    # ref_symbols = ['CU'] #开盘时间参考 TODO 测试带夜盘的和不带夜盘的测试
    # ref_future_index = g.si.get_future_index(g.future_symbol)
    ref_future_index = 'AG9999.XSGE'
    # 运行函数（reference_security为运行时间的参考标的；传入的标的只做种类区分，因此传入'IF1512.CCFX'或'IH1602.CCFX'是一样的）
    # 开盘前运行
    run_daily( before_market_open, time='before_open', reference_security=ref_future_index)
    # 开盘时运行
    # run_daily( while_open, time='open', reference_security=ref_future_index)
    # 收盘后运行
    run_daily( after_market_close, time='after_close', reference_security=ref_future_index)

    # 参照股指期货的时间每分钟运行一次, 必须选择分钟回测, 否则每天执行
    run_daily(market_open_run_per_minute, 'every_bar', reference_security=ref_future_index)


def set_params(context):
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    
    
## 开盘前运行函数     
def before_market_open(context):
    ## 获取要操作的期货(g.为全局变量)
    # 获取当月期货合约 Most Active Contract
    future_symbol_to_buy = ['AG']
    
    g.orders_unfinished = {}

    contracts_to_buy = []
    for future_symbol in future_symbol_to_buy:
        main_contract = get_dominant_future(future_symbol)
        contracts_to_buy.append(main_contract)

    days = g.ts.get_max_prices_days()
    securities_data_history = {}
    """可购买池新增"""
    for security in contracts_to_buy:
        prices = attribute_history(security, days, '1d',('high','low','close','pre_close'))

        sec_info = get_security_info(security)

        securities_data_history[security] = {}
        securities_data_history[security]['prices'] = prices
        securities_data_history[security]['end_date'] = sec_info.end_date
        securities_data_history[security]['type'] = sec_info.type
        securities_data_history[security]['in_buy_list'] = True
        securities_data_history[security]['main_contract'] = security

    """之前已有持仓的"""
    securities_info_to_refresh = g.ts.securities_info_to_refresh()
    for security in securities_info_to_refresh:
        securities_data_history[security] = {}
        securities_data_history[security]['prices'] = attribute_history(security, days, '1d',('high','low','close','pre_close'))
        securities_data_history[security]['main_contract'] = get_dominant_future(g.si.future_contract2symbol(security))

    g.ts.refresh_basic_data(context.portfolio, securities_data_history)
    
    # 检查、移仓
    orders = g.ts.futures_contracts_rollover()
    place_orders(orders)

    
def market_open_run_per_minute(context):
    """ 开盘期间每分钟运行 """

    data = get_current_data()
    # 执行委托
    """
    [sec, -position, 'sell_for_cash', sec_info_data[sec]['current_price'], 'long', self.pindex]
    """
    orders = g.ts.trade_strategy(context.portfolio, data)
    place_orders(orders)
    check_unfinished_orders()
    

def place_orders(orders):

    """ 订单委托 """
    for o in orders:
        sec = o[0]
        position = o[1]
        order_type = o[2]
        side = o[4]
        pindex = o[5]
        """
        UserOrder({'order_id': 1648647936, 'security': '601898.XSHG', 'amount': 3200, 'filled': 3200, 'price': 8.03, 'status': held, 'add_time': datetime.datetime(2022, 3, 7, 9, 31), 'side': 'long', 'action': 'open', 'pindex': 1, 'style': MarketOrderStyle: _limit_price=0.0})
        """
        r = order(sec, position, pindex=pindex, side=side)
        if r is not None:
            # 订单执行成功
            if r.status == OrderStatus.held:
                g.ts.after_order_success(r, order_type)
            else:
                # 简单处理 TODO 处理所有状态
                g.orders_unfinished[r.order_id] = o
        else:
            """ 如需要详细原因调整 log.order 级别到warning """
            log.warning("委托不成功")


def check_unfinished_orders():
    """ 检查之前未完成的是否完成了 """

    orders_unfinished = {}
    for order_id in g.orders_unfinished:
        orders =  get_orders(order_id=order_id)
        order_type = g.orders_unfinished[order_id][2]

        if orders[order_id].status == OrderStatus.held: # 订单执行成功
            g.ts.after_order_success(orders[order_id], order_type)
        else:                                           # 订单执行不成功
            orders_unfinished[order_id] = g.orders_unfinished[order_id]
    g.orders_unfinished = orders_unfinished
    pass


## 收盘后运行函数  
def after_market_close(context):
    pass


########################## 自定义函数 #################################


########################## 获取期货合约信息，请保留 #################################


from securities_info import *
# 此行需要替换为文件 turtle_system.py 中的内容
from turtle_system import *

